<?php

namespace App\Jobs;

use App\Models\UserWallet;
use App\Models\UserWithdraw;
use App\Services\Base\CacheService;
use App\Services\Base\HelpService;
use App\Services\BlockChainApiServices;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;

class SendTransaction implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    /**
     * @var $transaction UserWithdraw
     */
    protected $transaction;

    protected $type; //1提现

    public $timeout = 120; //设置超时时间120s

    public function __construct($type, $transaction)
    {
        $this->transaction = $transaction;
        $this->type = $type;
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        Log::channel('chain')->info("SendTransaction:" . $this->type . "|" . $this->transaction->id);
        try {
            $chain = $this->transaction->chain ?? "BSC";
            $chain_service = new BlockChainApiServices($chain);
            switch ($this->type) {
                case 1: //提现
                    /**
                     * @var $user_withdraw  UserWithdraw
                     */
                    $user_withdraw = UserWithdraw::query()->where('id', $this->transaction->id)->first();
                    if ($user_withdraw->tx_status != TX_STATUS_PROCESSING) {
                        Log::channel('chain')->info("SendTransaction:tx_status" . $user_withdraw->tx_status . "|" . $this->transaction->id);
                        return;
                    }
                    $from_address = $this->transaction->from_address;

                    /**
                     * @var $user_wallet UserWallet
                     */
                    $user_wallet = UserWallet::query()->where('address', $from_address)->first();
                    $from_key = $user_wallet->key;
                    $decimal = $chain_service->getWei($chain);
                    $contract = config("coins.withdraw_contract.$chain");
                    if ($contract) {
                        $balance = $chain_service->balanceToken($from_address, $chain_service->getContract($chain), $decimal);
                        if ($balance < $this->transaction->real_amount) {
                            Log::channel('chain')->info("SendTransaction:余额不足" . $balance . "|" . $this->transaction->real_amount);
                            CacheService::set("balance_not_sufficient", 1);
                            $this->transaction->update([
                                'tx_status' => TX_STATUS_FAIL,
                            ]);
                            return;
                        }
                        $send_result = $chain_service->sendToken(
                            $from_address,
                            $from_key,
                            $contract,
                            $this->transaction->to_address,
                            $this->transaction->real_amount,
                            $decimal);
                    } else {
                        $send_result = $chain_service->send($from_address,
                            $from_key,
                            $this->transaction->to_address,
                            $this->transaction->real_amount,
                            $chain_service->getSystemWei($chain));
                    }

                    if ($send_result['tx_id']) {
                        $this->transaction->update([
                            'executed_tx' => $send_result['tx_id'],
                            'tx_status' => TX_STATUS_SEND,
                            'status' => TRADE_STATUS_PROCESSING
                        ]);
                    } else {
                        $this->transaction->update([
                            'tx_status' => TX_STATUS_FAIL,
//                            'status' => TRADE_STATUS_FAIL, //如果是链失败还在处理中
                        ]);
                    }
                    break;
            }
        } catch (\Throwable $e) {
            $this->transaction->update([
                'tx_status' => TX_STATUS_FAIL,
//                'status' => TRADE_STATUS_FAIL,
            ]);
            HelpService::forceLog($e, json_encode($this->transaction), 'chain');
        }
    }
}
